const PENDING = 'pending' // 等待状态
const FULFILLED = 'fulfilled' //成功状态
const REJECTED = 'rejected' // 失败状态

class MyPromise {
	constructor(handle) {
		try {
			handle(this.onResolve, this.onReject)
		} catch (err) {
			this.onReject(err)
		}
	}
	status = PENDING // 状态，默认为pending
	resolveData = null // resolve时返回的数据
	rejectData = null // reject时返回的数据
	onFulfilledList = [] // resolve时执行的回调队列
	onRejetedList = [] // reject时执行的回调队列

	/**
	 * 成功回调
	 * @param {*} value 
	 */
	onResolve = value => {
		// 如果是penging状态，才会执行
		if (this.status === PENDING) {
			this.status = FULFILLED // 成功时 penging -> fulfilled
			this.resolveData = value //
			this.onFulfilledList.forEach(fn => {
				fn(this.resolveData)
			})
		}
	}
	/**
	 * 失败回调
	 * @param {*} err 
	 */
	onReject = err => {
		// 如果是penging状态，才会执行
		if (this.status === PENDING) {
			this.status = REJECTED // 成功时 penging -> rejected
			this.rejectData = err //
			this.onRejetedList.forEach(fn => {
				fn(this.rejectData)
			})
		}
	}

	/**
	 * promise解析，实现then的链式调用
	 * @param {当前then返回的数据} data 
	 * @param {当前then的resolve} resolve 
	 * @param {当前then的reject} reject 
	 */
	resolvePromise = (data, resolve, reject) => {
		// then 返回的数据为promise
		if (data instanceof MyPromise) {
			if (data.status === PENDING) {
				data.then(value => {
					this.resolvePromise(value, resolve, reject)
				}, reject)
			} else if (data.status === FULFILLED) {
				resolve(data.resolveData)
			} else {
				reject(data.rejectData)
			}
		}
		else { // then返回的是基本数据或undefined
			resolve(data)
		}
	}

	/**
	 * then回调，返回一个promise
	 * @param {成功} successCB 
	 * @param {失败} failCB 
	 */
	then (successCB = _ => _, failCB = reason => { throw reason }) {
		let promise
		if (this.status === PENDING) {
			// 状态为pending时，往回调队列中增加回调
			promise = new MyPromise((resolve, reject) => {
				this.onFulfilledList.push(() => {
					try {
						let result = successCB(this.resolveData)
						this.resolvePromise(result, resolve, reject)
					} catch (e) {
						reject(e);
					}
				})

				this.onRejetedList.push(() => {
					try {
						let result = failCB(this.rejectData)
						this.resolvePromise(result, resolve, reject)
					} catch (e) {
						reject(e);
					}
				})
			})
		} else if (this.status === FULFILLED) {
			// 状态为成功时，根据返回值返回新的promise
			promise = new MyPromise((resolve, reject) => {
				try {
					let result = successCB(this.resolveData)
					this.resolvePromise(result, resolve, reject)
				} catch (e) {
					reject(e);
				}
			})
		} else {
			// 状态失败时，根据返回值返回新的promise
			promise = new MyPromise((resolve, reject) => {
				try {
					let result = failCB(this.rejectData)
					this.resolvePromise(result, resolve, reject)
				} catch (e) {
					reject(e);
				}
			})
		}
		return promise
	}

	catch (failCB) {
		return this.then(undefined, failCB)
	}

	/**
	 * resolve方法
	 * @param {*} value 
	 */
	static resolve (value) {
		if (value instanceof MyPromise) return value
		return new MyPromise(resolve => resolve(value))
	}

	/**
	 * reject方法
	 * @param {*} reason 
	 */
	static reject (reason) {
		if (reason instanceof MyPromise) return reason
		return new MyPromise((resolve, reject) => reject(reason))
	}

	/**
	 * all方法
	 * @param {*} arr 
	 */
	static all (arr) {
		let result = []
		let idx = 0
		return new MyPromise((resolve, reject) => {
			function addData (key, value) {
				result[key] = value
				idx++
				if (idx === arr.length) {
					resolve(result)
				}
			}
			for (let i = 0; i < arr.length; i++) {
				let current = arr[i]
				if (current instanceof MyPromise) {
					// 如果是promise 对象
					current.then(value => addData(i, value), reason => reject(reason))
				} else {
					// 如果传入的不是promise，则直接作为结果填入结果数组中
					addData(i, arr[i])
				}
			}
		})
	}

	/**
	 * race方法
	 * @param {*} arr 
	 */
	static race (arr) {
		// 如果有promise执行完成，则设置为true，返回结果
		let flag = false
		return new MyPromise((resolve, reject) => {
			arr.forEach(item => {
				if (item instanceof MyPromise) {
					item.then(value => {
						if (!flag) {
							flag = true
							resolve(value)
						}
					}, err => {
						if (!flag) {
							flag = true
							reject(err)
						}
					})
				} else {
					// 如果传入的不是promise，则直接作为结果
					if (!flag) {
						flag = true
						resolve(item)
					}
				}
			})
		})
	}
}

module.export = MyPromise

